﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

using Xc.DataAccess.Core;
using Xc.DataAccess.Core.Services;

namespace Xc.DataAccess.HyperTerminalCore.Services
{
    /// <summary>
    /// 客户端在线信息
    /// </summary>
    public class UdpClientOnlineInfo:ViewModelBase
    {
        /// <summary>
        /// 扩展属性
        /// </summary>
        public object Property { get; set; }
        public UdpClientOnlineInfo(IPEndPoint iPEndPoint,UdpClient udpClient,Encoding encoding)
        {
            IPEndPoint = iPEndPoint;
            udpClient1 = udpClient;
            this.encoding1 = encoding;
        }
        private readonly Encoding encoding1;
        private readonly UdpClient udpClient1;
        /// <summary>
        /// 设备地址
        /// </summary>
        public string Address => IPEndPoint.ToString();
        IPEndPoint iPEndPoint;
        public IPEndPoint IPEndPoint
        {
            get => iPEndPoint;
            set
            {
                if (iPEndPoint == value)
                {
                    return;
                }

                iPEndPoint = value;
                RaisedPropertyChanged(); 
                RaisedPropertyChanged(nameof(Address));
            }
        }
        internal void ReceiveData(byte[] data)
        {
            if (!UseReceive)
            {
                ReceiveQueue.Enqueue(data);
            }
            Task.Run(() => { ReceiveMessage?.Invoke(this, data); });
        }
        System.Collections.Concurrent.ConcurrentQueue<byte[]> ReceiveQueue = new ConcurrentQueue<byte[]>();
        /// <summary>
        /// 获取应答列表
        /// </summary>
        /// <param name="clear"></param>
        /// <returns></returns>
        public byte[] GetResponds(bool clear)
        {
            if (clear)
            {
                List<byte> vs = new List<byte>();
                while (ReceiveQueue.TryDequeue(out var dats))
                {
                    vs.AddRange(dats);
                }
                return vs.ToArray();
            }
            else
            {
              return  ReceiveQueue.ToArray().SelectMany(p => p).ToArray();
            }
        }

        /// <summary>
        /// 使用接收功能
        /// </summary>
          bool UseReceive = true;
        public event Action<UdpClientOnlineInfo,byte[]> ReceiveMessage;
        public event Action<UdpClientOnlineInfo, byte[]> SendMessage;
        public async Task<T> SendHasRespond<T>(Func<UdpClientOnlineInfo,Task<T>> callback)
        {
            UseReceive = false;
           var res= await callback?.Invoke(this);
            UseReceive = true;
            return res;
        }
        /// <summary>
        /// 将指定数据发送出去
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<Result> Send(byte[] data)
        {
            try
            {
                int count = data.Length;
            AGAIN:
                var res = await udpClient1.SendAsync(data, count, IPEndPoint);
                UpdateDateTime = DateTime.Now;
                if (res < count)
                {
                    count = count - res;

                    goto AGAIN;
                }
                SendMessage?.Invoke(this, data);
                return Result.Accept("发送成功");
            }
            catch (Exception err)
            {
                return Result.Reject(err.Message);
            }

        }
        /// <summary>
        /// 将数据发送出去
        /// </summary>
        /// <param name="text"></param>
        /// <param name="appendLine"></param>
        /// <returns></returns>
        public async Task<Result> Send(string text,bool appendLine)
        {
            if (!(encoding1  is HexEncoding))
            {
                if (appendLine)
                {
                    text += Environment.NewLine;
                }
            }
            try
            {
                var send = encoding1.GetBytes(text);
                return await Send(send);
            }
            catch (Exception err)
            {
                return Result.Reject(err.Message);
            }

        }
        DateTime updateDateTime = DateTime.Now;
        /// <summary>
        /// 更新时间
        /// </summary>
        public DateTime UpdateDateTime
        {
            get => updateDateTime;
            set
            {
                if (updateDateTime == value)
                {
                    return;
                }

                updateDateTime = value;
                RaisedPropertyChanged();
                RaisedPropertyChanged(nameof(ActiveTimeSpan));
            }
        }         /// <summary>
                  /// 通信时间
                  /// </summary>
        public TimeSpan ActiveTimeSpan => DateTime.Now - UpdateDateTime;

    }
}
